<?php
/* KAP

gestion des librairies et de la prog objet


file version 2005-05-18 15:19:49
*/

class waklibmanager extends wakCoreComponent {
	var $default_parameters=array(
		'path'=>'lib/',
		'files'=>array(
			/*name/class => file */
		),
		'dependencies'=>array(
			/* name => array(name,name,...)*/
		),
		'core_files'=>array(
			/*name/class => file */
		),
		'core_dependencies'=>array(
			/* name => array(name,name,...)*/
		)
	);
	var $objects=array(); // tableau de references d'instances uniques
	var $included=array(); // libraries included
	// var $config_file=""
/*----------------------------------------------------------------------------------------------
                                                                                    constructeur
----------------------------------------------------------------------------------------------*/
	function waklibmanager(& $controller) {
		// appel du constructeur parent
		$const=get_parent_class($this);
		parent::$const($controller);
		// scan automatique de la librairie en cas d'absence du fichier de config
		if (!is_file($this->config_file)) {
			$conf=$this->scanLib();
			//echo "<p>libraries scanned :</p><pre>"; print_r($conf); echo "</pre>";
			$this->writeParameters($conf);
			$this->parameters=$conf;
		}
		//echo "<pre>"; print_r($conf); echo "</pre>";
		// re-transformation des dependances de chaine séparée par espace en tableaux
		foreach ($this->parameters['dependencies'] as $lib => $needed)
			$this->parameters['dependencies'][$lib]=explode(' ',$needed);
		foreach ($this->parameters['core_dependencies'] as $lib => $needed)
			$this->parameters['core_dependencies'][$lib]=explode(' ',$needed);
		//echo "<pre>"; print_r($this->parameters); echo "</pre>";
	}
/*-------------------------------------------------------------------------------------------------
 API / methodes publiques
-------------------------------------------------------------------------------------------------*/
	// retourne une instance la classe, avec passage de zéro à cinq arguments
	function & needObject($class,$args=array()) {
		if (!$this->needClass($class)) return false;
		// instanciation de la classe avec passage des arguments
		$inst=$this->createInstanceWithArgs($class,$args);
		return $inst;
	}
	// idem, mais concerne les librairies du noyau
	function & needCoreObject($class,$args=array()) {
		// inclusion
		$file=WAK_CORE_PATH.'lib/'.$this->parameters['core_files'][$class];
		if (!is_file($file)) return false;
		include_once($file);
		// instanciation de la classe avec passage des arguments
		$inst=$this->createInstanceWithArgs($class,$args);
		return $inst;
	}
	// renvoie la reference d'une instance unique de la classe
	// instancie la classe si nécessaire, avec passage de zéro à cinq arguments
	function & needUniqueObject($name, $class='',$args=array()) {
		if (isset($this->objects[$name])) return $this->objects[$name];
		if (!$class) $class=$name;
		if (!$this->needClass($class)) return false;
		// instanciation de la classe avec passage des arguments
		$instance=$this->createInstanceWithArgs($class,$args);
		if (!is_object($instance)) return false;
		$this->objects[$name]=& $instance;
		return $instance;
	}
	function needFunction($name) {
		return $this->needLibrary($name);
	}
	function needClass($name) {
		if (class_exists($name)) return true;
		$this->needLibrary($name);
		if (!class_exists($name)) {
			trigger_error("waklibManager: class $name still undefined after inclusion",E_USER_WARNING);
			return false;
		}
		return true;
	}
	function needLibrary($name) {
		$name=strtolower($name);
		if (isset($this->included[$name])) return true;
		// premiere recherche dans les librairies standards
		if (isset($this->parameters['files'][$name])) {
			// dependances
			if (isset($this->parameters['dependencies'][$name])) {
				foreach ($this->parameters['dependencies'][$name] as $needed)
					if (!$this->needLibrary($needed)) return false;
			}
			$filename=$this->parameters['path'].$this->parameters['files'][$name];
		// deuxieme recherche dans les librairies du noyau
		} else if (isset($this->parameters['core_files'][$name])) {
			// dependances
			if (isset($this->parameters['core_dependencies'][$name])) {
				foreach ($this->parameters['core_dependencies'][$name] as $needed)
					if (!$this->needLibrary($needed)) return false;
			}
			$filename=WAK_CORE_PATH.'lib/'.$this->parameters['core_files'][$name];
		// librairie non trouvée
		} else {
			trigger_error("waklibManager: library $name unknown",E_USER_WARNING);
			$this->included[$name]=false;
			return false;
		}
		if (!include_once($filename)) {
			//trigger_error()
			$this->included[$name]=false;
			return false;
		}
		$this->included[$name]=true;
		wakLog("libManager: $name => $filename included");
		return true;
		//$this->C->log("librairie $name incluse / library $name included");
		//return true;
	}
	
	function scanLib() {
		$conf=$this->getDefaultParameters();
		$lib=$this->scanFolder($conf['path']);
		//$lib=$this->scanFolder('lib/');
		//echo affvar($lib);
		$conf['files']=$lib['files'];
		$conf['dependencies']=$lib['dependencies'];
		$corelib=$this->scanFolder(WAK_CORE_PATH.'lib/');
		$conf['core_files']=$corelib['files'];
		$conf['core_dependencies']=$corelib['dependencies'];
		//echo affvar($conf);
		return $conf;
	}
	
/*----------------------------------------------------------------------------------------------
																										methodes privees
----------------------------------------------------------------------------------------------*/
	function & createInstanceWithArgs($class, $args=array()) {
		switch (true) {
		case count($args)==1:
			$instance=&new $class($args[0]);
			break;
		case count($args)==2:
			$instance=&new $class($args[0],$args[1]);
			break;
		case count($args)==3:
			$instance=&new $class($args[0],$args[1],$args[2]);
			break;
		case count($args)==4:
			$instance=&new $class($args[0],$args[1],$args[2],$args[3]);
			break;
		case count($args)>=5:
			$instance=&new $class($args[0],$args[1],$args[2],$args[3],$args[4]);
			break;
		default: // pas d'argument supplémentaires
			$instance=&new $class();
		}
		//echo affvar($instance);
		if (!is_object($instance)) {
			trigger_error("waklibManager: failed to create object of class $class",E_USER_WARNING);
			return false;
		}
		wakLog("libManager: instance of $class created");
		return $instance;
	}
	
	// scanne un dossier pour les classes et fonctions incluses
	// tente egalement de detecter les dependances
	// retourne un tableau sous la forme filename => array functions
	function scanFolder($path,$recurse=true) {
		// listage des fichiers du chemin
		$list=wakFileListPath($path,$recurse); // echo wakaffvar($list,"files into $path");
		// echo "<pre>"; var_dump($list); echo "</pre>";
		// print_r($list);
		// regex de nom de classe ou de fonction
		$ereg_name="[a-zA-Z][a-zA-Z0-9_]*";
		$files=array(); $dependances=array();
		// parcours des fichiers
		foreach ($list as $file) {
			// esquive des fichiers non php
			if (wakFileGetMimeType($file)!="text/php") {
				echo "$file not text/php";
				continue;
			}
			// coupure du chemin initial
			$filename=substr($file,strlen($path));
			$fileLibraries=array();
			// recherche des classes
			$foundClasses=wakFileRegexSearchContent("class +($ereg_name)( +extends ($ereg_name))? +{",$file);
			//echo affvar($foundClasses,false);
			echo "<pre>"; var_dump($foundClasses); echo "</pre>";
			if ($foundClasses) {
				// definition du tableau files, et des dependances basées sur l'héritage
				foreach ($foundClasses as $result) {
					//echo affvar($result);
					if (!is_array($result)) continue;
					$name=strtolower($result['captured'][0]);
					$fileLibraries[]=$name;
					// ajout dans la liste des librairies et de leur emplacement
					$files[$name]=$filename;
					// ajout de dépendances basées sur l'héritage
					if (!$parent=$result['captured'][2]) continue;
					$dependances[$name]=array(strtolower($parent));
				}
			} else {
				// pas de classe trouvée, recherche des fonctions
				//echo "<p>no class in $file</p>";
				$foundFunctions=wakFileRegexSearchContent("function +($ereg_name)",$file);
				foreach ($foundFunctions as $result) {
					if (!is_array($result)) continue;
					$name=strtolower($result['captured'][0]);
					$fileLibraries[]=$name;
					// ajout dans la liste des librairies et de leur emplacement
					$files[$name]=$filename;
				}
			}
			// recherche des dépendances
			// instanciation(s)
			$foundInst=wakFileRegexSearchContent("new +($ereg_name)\(",$file);
			foreach ($foundInst as $result) {
				$name=strtolower($result['captured'][0]);
				foreach ($fileLibraries as $lib) {
					if ($name!=$lib
					and (!isset($dependances[$lib]) or !in_array($name,$dependances[$lib])))
						$dependances[$lib][]=$name;
				}
			}
			// appel(s) statique(s)
			$foundCalls=wakFileRegexSearchContent("($ereg_name)::$ereg_name\(",$file);
			foreach ($foundCalls as $result) {
				$name=strtolower($result['captured'][0]);
				foreach ($fileLibraries as $lib) {
					if ($name!=$lib 
					and (!isset($dependances[$lib]) or !in_array($name,$dependances[$lib])))
						$dependances[$lib][]=$name;
				}
			}
		}
		ksort($files);
		// transformation des tableaux de dépendance en chaines séparées par un espace
		foreach ($dependances as $lib => $dep) {
			$dependances[$lib]=join(' ',$dep);
		}
		trigger_error("wakLibManager: scanned $path, found ".count($files)." libraries");
		$scan=array(
			'files'=>$files,
			'dependencies'=>$dependances
		);
		echo "<pre>"; var_dump($scan); echo "</pre>";
		return $scan;
	}
}
?>
